#include <signal.h>
#include <iostream>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#include <sys/wait.h>
#include <cstring>
#include <sstream>
using namespace std;

int pipe_fd; // 全局变量，用于在信号处理函数中访问管道

void sighandle(int signo)
{
    if (signo == SIGIO)
    {
        cout << "父进程收到SIGIO信号" << endl;
        
        char buffer[1024];
        while (true)
        {
            int n = read(pipe_fd, buffer, sizeof(buffer) - 1);
            
            if (n > 0)
            {
                buffer[n] = 0;
                cout << "子进程写入: " <<endl << buffer <<endl;
            }
            else if (n == -1 && errno == EAGAIN)
            {
                // 非阻塞读取，没有数据时立即返回
                cout << "管道已无数据，信号执行结束" << endl<<endl;
                break;
            }

        }
    }
}



int main()
{
    int pipefd[2];
    pid_t pid;
    
    // 创建匿名管道
    if (pipe(pipefd) == -1)
    {
        perror("pipe创建失败");
        return 1;
    }
    
    // 创建子进程
    pid = fork();
    
    if (pid == 0) 
    {
        // 子进程 - 写入端
        close(pipefd[0]); // 关闭读取端
        
        sleep(1);//等待父进程将信号捕捉号还有管道描述符都设置好

        int i=0;
        // 向管道写入数据
        while(1)
        {
            stringstream ss;
            string s="消息";
        
            ss<<s<<i++<<"\n"<<s<<i++;
            string rst= ss.str();
            write(pipefd[1],rst.c_str(), rst.size());

            sleep(3);
        }
    }
    else
    {
        // 父进程 - 读取端
        close(pipefd[1]); // 关闭写入端
        
        pipe_fd= pipefd[0];

        // 设置信号处理函数
        signal(SIGIO, sighandle);
        
        // 设置管道读取端为非阻塞和异步模式
        int flags = fcntl(pipe_fd, F_GETFL);//获取文件状态标志
        fcntl(pipe_fd, F_SETFL, flags | O_NONBLOCK | O_ASYNC);//设置文件状态标志
        fcntl(pipe_fd, F_SETOWN, getpid());//设置属主进程
        

        while (true)
        {
            sleep(1);
        }
        
        close(pipe_fd);
    }
    
    return 0;
}